package com.fangda.network.tcp.server;

import com.fangda.network.NetworkConfig;
import com.fangda.network.NetworkMessage;
import com.fangda.network.NetworkMessageCallback;
import com.fangda.network.NetworkType;
import com.fangda.network.tcp.AbstractTcpNetwork;
import io.vertx.core.net.NetServer;
import io.vertx.core.net.NetSocket;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.java.Log;

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * TCP服务网络组件
 */
@Log
public class TcpServerNetwork extends AbstractTcpNetwork {

    @Setter
    @Getter
    private NetServer server;

    protected final static List<NetSocket> SESSIONS = new CopyOnWriteArrayList<>();

    public TcpServerNetwork(String id, NetworkConfig config) {
        super(id, config);
    }

    @Override
    public NetworkType getNetworkType() {
        return NetworkType.TCP_SERVER;
    }

    public void startup() {
        server.connectHandler(socket -> {
            this.setAlive(true);
            initSocket(socket, SESSIONS);
            SESSIONS.add(socket);
            if(callback != null) {
                callback.connectionChange(true, null);
            }
        });
        server.listen(config.getPort(), config.getIp(), res -> {
            setAlive(res.succeeded());
            if(callback != null) {
                callback.connectionChange(res.succeeded(), res.cause());
            }
        });
    }

    @Override
    public void shutdown() {
        if(server != null) {
            server.close(r -> {
                setAlive(!r.succeeded());
                SESSIONS.clear();
                if(callback != null) {
                    callback.connectionChange(false, null);
                }
            });
        } else {
            this.setAlive(false);
            SESSIONS.clear();
        }
    }

    @Override
    public void reload() {
        shutdown();
        startup();
    }

    public void send(NetworkMessage message, NetworkMessageCallback messageCallback) {
        for(NetSocket socket : SESSIONS) {
            this.send(socket, message, messageCallback);
        }
    }

    public void send(NetworkMessage message, NetworkMessageCallback messageCallback, List<NetSocket> sessions) {
        for(NetSocket socket : SESSIONS) {
            if(!sessions.contains(socket)) {
                continue;
            }
            this.send(socket, message, messageCallback);
        }
    }

    public List<NetSocket> getSessions() {
        return SESSIONS;
    }
}
